/* * Sun Public License Notice * * The contents of this file are subject to the Sun Public License * Version 1.0 (the "License"). You may not use this file except in * compliance with the License. A copy of the License is available at * http://www.sun.com/ * * The Original Code is Forte for Java, Community Edition. The Initial * Developer of the Original Code is Sun Microsystems, Inc. Portions * Copyright 1997-2000 Sun Microsystems, Inc. All Rights Reserved. */ package org.netbeans.modules.debugger.support.nodes; import java.awt.Image; import java.awt.Toolkit; import java.beans.*; import java.lang.reflect.InvocationTargetException; import java.util.ResourceBundle; import java.lang.ref.WeakReference; import org.openide.NotifyDescriptor; import org.openide.TopManager; import org.openide.actions.PropertiesAction; import org.openide.actions.ToolsAction; import org.openide.debugger.DebuggerException; import org.openide.debugger.DebuggerNotFoundException; import org.openide.debugger.Debugger; import org.openide.nodes.Node; import org.openide.nodes.Sheet; import org.openide.nodes.Children; import org.openide.nodes.AbstractNode; import org.openide.nodes.PropertySupport; import org.openide.text.Line; import org.openide.util.NbBundle; import org.openide.util.actions.SystemAction; import org.openide.util.actions.CallableSystemAction; import org.netbeans.modules.debugger.support.DebuggerAdapter; import org.netbeans.modules.debugger.support.AbstractDebugger; import org.netbeans.modules.debugger.support.AbstractThread; import org.netbeans.modules.debugger.support.actions.SuspendResumeAction; import org.netbeans.modules.debugger.support.actions.SwitchOnAction; import org.netbeans.modules.debugger.support.actions.SuspendCookie; import org.netbeans.modules.debugger.support.actions.SwitchOnCookie; import org.netbeans.modules.debugger.support.actions.GoToSourceCookie; import org.netbeans.modules.debugger.support.actions.GoToSourceAction; /** * This class representates threads and threadGroups as a Node. * This class is final only for performance reasons, can be happily * unfinaled if desired. * * @author Jan Jancura */ public final class ThreadNode extends AbstractNode implements SuspendCookie, SwitchOnCookie, GoToSourceCookie { /** generated Serialized Version UID */ static final long serialVersionUID = 2202990736781011814L; // static .................................................................... /** Property names */ public static final String PROP_THREAD_NAME = "threadName"; // NOI18N public static final String PROP_THREAD_STATE = "threadState"; // NOI18N public static final String PROP_THREAD_CLASS = "threadClass"; // NOI18N public static final String PROP_THREAD_METHOD = "threadMethod"; // NOI18N public static final String PROP_THREAD_LINE = "threadLine"; // NOI18N public static final String PROP_THREAD_STACK_DEPTH = "threadStackDepth"; // NOI18N public static final String PROP_THREAD_FRAME_INDEX = "threadFrameIndex"; // NOI18N public static final String PROP_THREAD_SUSPENDED = "threadSuspended"; // NOI18N public static final int STATE_MAIN = 1; public static final int STATE_STOPPED = 2; protected static String ICON_CURRENT = "/org/netbeans/modules/debugger/resources/threadCurrent"; // NOI18N protected static String ICON_SUSPENDED = "/org/netbeans/modules/debugger/resources/threadSuspended"; // NOI18N protected static String ICON_RUNNING = "/org/netbeans/modules/debugger/resources/threadRunning"; // NOI18N /** Icons for threads. */ protected static Image threadFolderIcon; protected static Image threadFolderIcon32; protected static Image threadCurrentIcon; protected static Image threadCurrentIcon32; protected static Image threadRunningIcon; protected static Image threadRunningIcon32; /** System actions of this node */ private static SystemAction[] staticActions; private static ResourceBundle bundle; // variables ................................................................. private AbstractDebugger debugger; private AbstractThread thread; private ThreadListener threadListener; private Node[] children = null; private CallStackNode callStack; private LocalesRootNode locales; private int state = 4; /** Where to add variables. */ private VariableHome variableHome; private boolean oldSuspended = false; // init ...................................................................... /** * Creates ThreadNode. */ public ThreadNode (VariableHome variableHome, AbstractThread thread) { super (new Children.Array()); this.variableHome = variableHome; this.thread = thread; initialize(); //S ystem.out.println ("Thread created " + num++); // NOI18N } //static int num = 0; /** * Remove listeners. */ protected void finalize () { //S ystem.out.println ("Thread destroyed " + --num); // NOI18N debugger.removePropertyChangeListener (threadListener); thread.removePropertyChangeListener (threadListener); } /** Performs basic initialization of children, listeners, etc. */ private void initialize () { initializeChildren (); setName (); createProperties (); getCookieSet ().add (this); try { debugger = (AbstractDebugger) TopManager.getDefault ().getDebugger (); } catch (DebuggerNotFoundException ex) { TopManager.getDefault ().notifyException (ex); return; } threadListener = new ThreadListener ( this ); debugger.addPropertyChangeListener (threadListener); thread.addPropertyChangeListener (threadListener); } /** Initializes children (subnodes) of this node */ private void initializeChildren () { Children myChildren = getChildren (); myChildren.add ( new Node[] { callStack = new CallStackNode (variableHome, thread), locales = new LocalesRootNode (variableHome, thread) } ); } // Node implementation ....................................................... /** Method that prepares properties. Called from initialize. */ private void createProperties () { // default sheet with "properties" property set // NOI18N Sheet sheet = Sheet.createDefault(); Sheet.Set props = sheet.get(Sheet.PROPERTIES); props.put (new PropertySupport.ReadOnly ( PROP_THREAD_NAME, String.class, getLocalizedString ("PROP_thread_name"), getLocalizedString ("HINT_thread_name") ) { public Object getValue () throws InvocationTargetException { try { return thread.getName (); } catch (java.lang.Exception e) { throw new InvocationTargetException (e); } } }); props.put (new PropertySupport.ReadOnly ( PROP_THREAD_STATE, String.class, getLocalizedString ("PROP_thread_state"), getLocalizedString ("HINT_thread_state") ) { public Object getValue () throws InvocationTargetException { try { return thread.getState (); } catch (java.lang.Exception e) { throw new InvocationTargetException (e); } } }); props.put (new PropertySupport.ReadOnly ( PROP_THREAD_CLASS, String.class, getLocalizedString ("PROP_thread_class"), getLocalizedString ("HINT_thread_class") ) { public Object getValue () throws InvocationTargetException { try { return thread.getClassName (); } catch (java.lang.Exception e) { throw new InvocationTargetException (e); } } }); props.put (new PropertySupport.ReadOnly ( PROP_THREAD_METHOD, String.class, getLocalizedString ("PROP_thread_method"), getLocalizedString ("HINT_thread_method") ) { public Object getValue () throws InvocationTargetException { try { return thread.getMethod (); } catch (java.lang.Exception e) { throw new InvocationTargetException (e); } } }); props.put (new PropertySupport.ReadOnly ( PROP_THREAD_LINE, Integer.TYPE, getLocalizedString ("PROP_thread_line"), getLocalizedString ("HINT_thread_line") ) { public Object getValue () throws InvocationTargetException { try { return new Integer (thread.getLineNumber ()); } catch (java.lang.Exception e) { throw new InvocationTargetException (e); } } }); props.put (new PropertySupport.ReadOnly ( PROP_THREAD_STACK_DEPTH, Integer.TYPE, getLocalizedString ("PROP_thread_stack_depth"), getLocalizedString ("HINT_thread_stack_depth") ) { public Object getValue () throws InvocationTargetException { try { return new Integer (thread.getStackDepth ()); } catch (java.lang.Exception e) { throw new InvocationTargetException (e); } } }); props.put (new PropertySupport.ReadWrite ( PROP_THREAD_SUSPENDED, Boolean.TYPE, getLocalizedString ("PROP_thread_suspended"), getLocalizedString ("HINT_thread_suspended") ) { public Object getValue () throws InvocationTargetException { try { return new Boolean (thread.isSuspended ()); } catch (java.lang.Exception e) { throw new InvocationTargetException (e); } } public void setValue (Object val) throws InvocationTargetException { if (!(val instanceof Boolean)) throw new IllegalArgumentException (); setSuspended (((Boolean)val).booleanValue ()); } }); // and set new sheet setSheet (sheet); } /** Getter for set of actions that should be present in the * popup menu of this node. This set is used in construction of * menu returned from getContextMenu and specially when a menu for * more nodes is constructed. * * @return array of system actions that should be in popup menu */ public SystemAction[] getActions () { if (staticActions == null) staticActions = new SystemAction[] { SystemAction.get (SwitchOnAction.class), SystemAction.get (GoToSourceAction.class), SystemAction.get (SuspendResumeAction.class), null, SystemAction.get (ToolsAction.class), SystemAction.get (PropertiesAction.class) }; return staticActions; } /** * Returns default action. */ public SystemAction getDefaultAction () { return SystemAction.get (SwitchOnAction.class); } public void destroy () throws java.io.IOException { super.destroy (); debugger.removePropertyChangeListener (threadListener); thread.removePropertyChangeListener (threadListener); } // SwitchOnCookie ........................................................................................ /** * Sets this thread to be suspended. */ public boolean canSetCurrent () { return (!thread.isCurrent ()) && isSuspended (); } /** * Sets this thread to be current. */ public void setCurrent () { thread.setCurrent (true); } // SuspendCookie ............................................................. /** * Sets this thread to be suspended. */ public void setSuspended (boolean b) { try { thread.setSuspended (b); changeChildren (); } catch (DebuggerException e) { TopManager.getDefault ().notify ( new NotifyDescriptor.Exception ( e.getTargetException (), getLocalizedString ("EXC_Debugger") + ": " + e.getMessage () ) ); } } /** * Sets this thread to be suspended. */ public boolean isSuspended () { try { return thread.isSuspended (); } catch (DebuggerException e) { return false; } } // GoToSourceCookie implementation ........................................... /** * Goes to source. */ public void goToSource () { try { Line l = thread.getLine (); if (l != null) l.show (Line.SHOW_GOTO); } catch (DebuggerException e) { } } /** * Returns true if source is availabled. */ public boolean canGoToSource () { try { Line l = thread.getLine (); if (l != null) return true; } catch (DebuggerException e) { } return false; } // helper methods ............................................................ /** * @return localized string. */ static String getLocalizedString (String s) { if (bundle == null) bundle = NbBundle.getBundle (ThreadNode.class); return bundle.getString (s); } /** * Sets curent icon (running thread, current thread, suspended thread). */ void refreshIcon () { if ((state & STATE_MAIN) != 0) { setIconBase (ICON_CURRENT); // NOI18N } else if ((state & STATE_STOPPED) != 0) { setIconBase (ICON_SUSPENDED); // NOI18N } else { setIconBase (ICON_RUNNING); // NOI18N } } /** equals if thread equals o.thread * @param o */ public final boolean equals (Object o) { return o instanceof ThreadNode && ((ThreadNode) o).thread.equals (thread); } /** * @return hashCode of thread */ public final int hashCode () { return thread.hashCode (); } /** * Updates name & icon, and fires change. */ void changeProperties () { setName (); firePropertyChange (null, null, null); } /** * Updates name & icon. */ void setName () { // read thread state int newS = 0; if (thread.isCurrent ()) newS = STATE_MAIN; try { if (thread.isSuspended ()) newS |= STATE_STOPPED; } catch (java.lang.Exception e) { } // change icon if (state != newS) { state = newS; refreshIcon (); } // update name try { String s = thread.getName () + " (" + thread.getState () + ")"; // NOI18N setDisplayName (s); setName (s); } catch (org.openide.debugger.DebuggerException e) { String s = getLocalizedString ("CTL_Thread"); setDisplayName (s); setName (s); } } /** * Refresh locales & callstack. */ void changeChildren () { boolean s = isSuspended (); if (oldSuspended || s) { if (s || (debugger.getLastAction () == AbstractDebugger.ACTION_GO)) { locales.changeChildren (); callStack.changeChildren (); } } oldSuspended = s; } AbstractThread getDebuggerThread () { return thread; } // innerclasses .............................................................. /** * Listens on thread and debugger. */ private static class ThreadListener implements PropertyChangeListener { private WeakReference node; private AbstractDebugger debugger; private AbstractThread thread; ThreadListener (ThreadNode n) { node = new WeakReference (n); debugger = n.debugger; thread = n.thread; } public void propertyChange (PropertyChangeEvent e) { ThreadNode tn = (ThreadNode) node.get (); if (tn == null) { debugger.removePropertyChangeListener (this); thread.removePropertyChangeListener (this); return; } if (e.getSource () instanceof AbstractDebugger) { if (!e.getPropertyName ().equals (debugger.PROP_STATE)) return; int debuggerState = debugger.getState (); if (debuggerState == Debugger.DEBUGGER_STARTING) return; tn.changeChildren (); } else { tn.changeProperties (); } } } } /* * Log * 13 Gandalf-post-FCS1.11.3.0 3/28/00 Daniel Prusa * 12 Gandalf 1.11 1/14/00 Daniel Prusa NOI18N * 11 Gandalf 1.10 1/13/00 Daniel Prusa NOI18N * 10 Gandalf 1.9 1/6/00 Jan Jancura Refresh of Threads & * Watches, Weakization of Nodes * 9 Gandalf 1.8 11/8/99 Jan Jancura Somma classes renamed * 8 Gandalf 1.7 11/5/99 Jan Jancura Default action updated * 7 Gandalf 1.6 10/23/99 Ian Formanek NO SEMANTIC CHANGE - Sun * Microsystems Copyright in File Comment * 6 Gandalf 1.5 10/11/99 Jan Jancura Bug in refreshing * callstacks * 5 Gandalf 1.4 10/1/99 Jan Jancura Current thread & bug * 4108 * 4 Gandalf 1.3 9/28/99 Jan Jancura * 3 Gandalf 1.2 9/15/99 Jan Jancura * 2 Gandalf 1.1 8/18/99 Jan Jancura Localization & Current * thread & Current session * 1 Gandalf 1.0 8/17/99 Jan Jancura * $ */